#ifndef LIBACCENT_ALGORITHMS_MAP_HPP
#define LIBACCENT_ALGORITHMS_MAP_HPP

#include "accent/utility/safe_position.hpp"
#include <utility>

namespace accent
{
  namespace detail
  {
    template <typename Base, typename Function>
    class mapped_range
    {
      Base base;
      Function function;

    public:
      mapped_range(Base base, Function function)
        : base(std::move(base)), function(std::move(function))
      {}

      bool empty() const { return base.empty(); }
      void pop_front() { base.pop_front(); }
      auto front() const -> decltype(function(base.front())) {
        return function(base.front());
      }

      using position = support::safe_position<Base>;
      position front_position() const { return base.front_position(); }
      mapped_range from(position p) const { return { base.from(p), function }; }
      mapped_range until(position p) const {
        return { base.until(p), function };
      }

      position back_position() const { return base.back_position(); }
      auto back() const -> decltype(function(base.front())) {
        return function(base.back());
      }
      void pop_back() { base.pop_back(); }

      std::size_t size() const { return base.size(); }
      void skip_front(std::size_t n) { base.skip_front(n); }
      void skip_back(std::size_t n) { base.skip_back(n); }
      auto operator [](std::size_t n) const
          -> decltype(function(base.front())) {
        return function(base[n]);
      }
    };
  }

  template <typename Base, typename Function>
  detail::mapped_range<Base, Function> map(Base base, Function function)
  {
    return { std::move(base), std::move(function) };
  }
}

#endif
